use json::JsonValue;
// use crate::i_result::IResult;
use crate::my_request;
use json::object::Object as JsonObject;
use percent_encoding::NON_ALPHANUMERIC;
use std::sync::mpsc::Sender;

pub fn add_channel(send: Sender<String>, pool: &crate::Pool, arg: String) {
    pool.execute(move || {
        handler(send, arg);
    });
}

/// webview 执行器
fn handler(send: Sender<String>, arg: String) {
    // println!("arg: {}", arg);
    let result = json::parse(arg.as_str()).unwrap_or(JsonValue::new_object());
    let map = match result {
        JsonValue::Object(v) => v,
        _ => JsonObject::new(),
    };

    let mut exec_js = None;
    let cmd = get_json_value(&map, "cmd").unwrap_or("not cmd".to_owned());
    let default = JsonValue::new_object();
    let json_value = match map.get("json_value").unwrap_or(&default) {
        JsonValue::Object(v) => v.to_owned(),
        _ => json::object::Object::new(),
    };
    match cmd.as_str() {
        "request" => request_handler(json_value, &mut exec_js),
        "database" => database_handler(json_value, &mut exec_js),
        _ => exec_js = Some(format!("console.log('{}')", "cmd is not supported")),
    }

    let exec_js = exec_js.unwrap_or("console.log('not execute runable')".to_owned());
    println!(
        "arg:{} exec_js: {}",
        &arg,
        exec_js.as_str().replace('\n', "")
    );

    if let Err(e) = send.send(exec_js) {
        println!("send.send error: {:?}", e);
    }
}

/// 数据库处理
fn database_handler(json_value: JsonObject, exec_js: &mut Option<String>) {
    let data_type = match get_json_value(&json_value, "type") {
        Some(v) => v,
        None => {
            *exec_js = Some(format!(
                "console.log('{}')",
                "database_handler type is not empty"
            ));
            return;
        }
    };
    let callback = match get_json_value(&json_value, "callback") {
        Some(v) => v,
        None => {
            *exec_js = Some(format!(
                "console.log('{}')",
                "database_handler callback is not empty"
            ));
            return;
        }
    };
    let key = match get_json_value(&json_value, "key") {
        Some(v) => v,
        None => {
            *exec_js = Some(format!(
                "console.log('{}')",
                "database_handler key is not empty"
            ));
            return;
        }
    };
    let tree_name = get_json_value(&json_value, "tree_name");
    match data_type.as_str() {
        "select" => {
            let result = match crate::database::select(key.as_str(), tree_name)
                .map_err(|e| format!("console.log('crate::database::select error {:?}')", e))
            {
                Ok(v) => v,
                Err(e) => Some(e),
            };
            match result {
                Some(v) => {
                    let js = format!("window.$EventBus.$emit('{}', '{}')", callback, v);
                    *exec_js = Some(js);
                }
                None => {
                    let js = format!("window.$EventBus.$emit('{}', null)", callback);
                    *exec_js = Some(js);
                }
            }
        }
        "insert" => {
            if let Some(value) = get_json_value(&json_value, "value") {
                let _ = crate::database::insert(key.as_str(), value.as_str(), tree_name);
            } else {
                *exec_js = Some(format!(
                    "console.log('{}')",
                    "database_handler insert value is empty"
                ));
            }
        }
        "remove" => {
            let _ = crate::database::remove(key.as_str(), tree_name);
        }
        _ => {
            *exec_js = Some(format!(
                "console.log('{}')",
                "database_handler type is not supper"
            ));
        }
    };
    println!("database_handler: {:?}", exec_js);
}

/// 请求执行器
fn request_handler(json_value: JsonObject, exec_js: &mut Option<String>) {
    let data = get_json_value(&json_value, "data").unwrap_or("".to_owned());
    let method_type = get_json_value(&json_value, "method").unwrap_or("not method".to_owned());
    let url = get_json_value(&json_value, "url").unwrap_or("not url".to_owned());
    let callback = get_json_value(&json_value, "callback").unwrap_or("not callback".to_owned());

    let mut handle_data = |v: String| {
        // let v = v.replace('\n', "").replace('\r', "");
        let v = v.trim();
        // println!("respone data: {}", &v.replace('\n', ""));
        //let encode = base64::encode_config(v.as_bytes(), URL_SAFE_NO_PAD);
        let js = {
            if v.starts_with("{") || v.starts_with("[") {
                format!("window.$EventBus.$emit('{}', {});", callback, v)
            } else {
                let encode =
                    percent_encoding::percent_encode(v.as_bytes(), NON_ALPHANUMERIC).to_string();
                format!(
                    "window.$EventBus.$emit('{}', {{ encode: '{}' }});",
                    callback, encode
                )
            }
        };

        *exec_js = Some(js);
    };

    let result = match method_type.to_lowercase().as_str() {
        "get" => my_request::reqwest_get(&url),
        "post" => my_request::reqwest_post(&url, data),
        _ => {
            *exec_js = Some(format!("console.log('{}')", "reqeust method not supported"));
            return;
        }
    };

    match result {
        Ok(v) => handle_data(v),
        Err(e) => println!("request error; url: {}, error:{:?}", &url, e),
    }
}

fn get_json_value(v: &JsonObject, k: &str) -> Option<String> {
    let default = JsonValue::String("".to_owned());
    let data = v.get(k).unwrap_or(&default).to_owned();
    let v = data.to_string();
    if v == "" {
        None
    } else {
        Some(v)
    }
}
